<?

	require_once 'Library/functions.php';

	final class Interface_SmRoot0v0r01 extends _smuoiAppInterface{
		
		function title(){
			return $this->args->title;	
		}
		
		function run(){
			if(!smuoi_is_root(usr())) httpE(401);
			
			$this->cxt = explode('/', $this->args->rf);
		
			if(isset($this->cxt[2])) httpE(404, 'what?');
			
			if(DOAJAX) return $this->run_ajax();
			
			if(!isset($this->cxt[1])){
				switch($cxt = @$this->cxt[0]){
					case '':
					case 'users':
					case 'groups':
					case 'domains':
					case 'databases':
						return $this->run_screen('choose');
					default:
						httpE(404, "no context '$cxt'");
				}
			}

			if(!$id = $this->cxt[1]) httpE(404, 'no id');
			
			switch($this->cxt[0]){
				case 'users':
					if(!$this->usr = smdb('u:'.$id)) httpE(404);
					return $this->run_screen('user');
				case 'groups':
					if(!$this->grp = smdb('g:'.$id)) httpE(404);
					return $this->run_screen('group');
				case 'domains':
					if(!$this->dom = Domain($id)) httpE(404);
					return $this->run_screen('domain');
				case 'databases':
					if(!$this->dtb = new ini(ETC_DIR."/db/$id")) httpE(404);
					$this->dbn = $id;
					return $this->run_screen('database');
				default:
					httpE(404);
			}
		}
		
		protected $ajax_methods = array('browse', 'newUser', 'newGroup', 'newDomain', 'newDatabase', 'duplicateDatabase', 'deleteDatabase', 'saveUser', 'saveGroup', 'saveDomain', 'testDatabase', 'saveDatabase');
	
		function browse($xa){
			switch(@$this->cxt[0]){
				case 'groups':
					return $this->browse_groups($xa);
				case 'users':
					return $this->browse_users($xa);
				case 'domains':
					return $this->browse_doms($xa);
				default:
					httpE(404);
			}	
		}
		
		function browse_groups($xa){
			$apps = serializeGroups(get_groups((@$xa->filter) ? explode(',', $xa->filter) : false));
			jsln("Browser.receive($apps);");
		}
		
		function browse_users($xa){
			$apps = serializeUsers(get_users((@$xa->filter) ? explode(',', $xa->filter) : false));
			jsln("Browser.receive($apps);");
		}
		
		function browse_doms($xa){
			$apps = serializeDoms(get_doms((@$xa->filter) ? explode(',', $xa->filter) : false));
			jsln("Browser.receive($apps);");
		}
	
		function newUser($xa){
			$new = smroot()->newUser();
			$j = new json($new->id, mkUserJsObj($new->data()));
			jsln("Apps.add($j);");
		}
		
		function newGroup($xa){
			$new = smroot()->newGroup();
			$j = new json($new->id, mkGroupJsObj($new->data()));
			jsln("Apps.add($j);");
		}
		
		function newDomain($xa){
			if(!$new = new DesktopDomain($xa->dom_id)) httpE(418, "Dom '$xa->dom_id' not found");
			$new->commit(1);
			$j = new json($new->id, mkDomJsObj($new->dbObj()->data()));
			jsln("Apps.add($j);");
		}
		
		function newDatabase($xa){
			$fil = HostInterface::filename_increment(ETC_DIR.'/db/newdb');
			$c = "type = mysql;\n"
				."name = db_name;\n"
				."host = localhost;\n"
				."user = db_user;\n"
				."pass = db_pass;\n\n"
				."[Fmgr/0v0r01/files]\n"
				."\tname = files\n"
				."\tkey = f\n"
				."\tcols = id,xst,dir,mod,stb,own,grp,fmrp,mime,filesize,checksum,title,tags,description,lstr,lobj,tmpl,usrp,created,updated,date,expires,class\n\n"
				."[Longtext/0v0r00/longtext]\n"
				."\tname = longtext\n"
				."\tkey = b\n"
				."\tcols = id,lnk,mem,blb,updated\n\n"
				."[Nicename/0v0r00/nicename]\n"
				."\tname = nicename\n"
				."\tkey = n\n"
				."\tcols = id,path,name,type,value\n";
			HostInterface::writeToFile($fil, $c);
			$n = basename($fil);
			$n = substr($n, 0, strrpos($n, '.'));
			$j = new json($n, object(
				'name', $n,
				'id', $n,
				'rel', $n,
				'title', $n,
				'icon', 'database.png',
				'modpath', 'SmRoot/0.1'
			));
			jsln("Apps.add($j);");			  
		}
		
		function duplicateDatabase($xa){
			$dbn = $xa->dbn;
			$fil = HostInterface::filename_increment(ETC_DIR."/db/$dbn");
			if(!copy(ETC_DIR."/db/$dbn", $fil)){
				echo "failed to duplicate $dbn";
				return;
			}
			$n = basename($fil);
			$j = new json($n, object(
				'name', $n,
				'id', $n,
				'rel', $n,
				'title', $n,
				'icon', 'database.png',
				'modpath', 'SmRoot/0.1'
			));
			jsln("Apps.add($j);");
		}
		
		function deleteDatabase($xa){
			$dbn = $xa->dbn;
			if(!$dbn) return;
			if(in_array($dbn, array('root', DOM_ID))){
				echo "Cannot delete the root or running databases";
				return;
			}
			if(unlink(ETC_DIR."/db/$dbn")){
				echo "deleted database $dbn";
				jsln("Apps.remove('$dbn'); Apps.loaded();");
				return;
			}
			echo "failed to delete $dbn";
		}
		
		function saveUser($xa){
			if(!$usr = smdb($xa->id)) httpE(418, "User '$xa->id' not found");
			foreach(array('name', 'email', 'pass', 'groups', 'class', 'home', 'can_symlink', 'can_script', 'can_apache') as $k) if(isset($xa->$k)) $usr->$k = $xa->$k;	
			$usr->commit();
			$j = new json($usr->data());
			foreach(array('can_script', 'can_apache', 'can_symlink') as $p) $j->$p = $usr->get($p);
			jsln("User.load($j);");
		}
		
		function saveGroup($xa){
			$grp = smdb($xa->id);
			foreach(array('name', 'members') as $k) if(isset($xa->$k)) $grp->$k = $xa->$k;
			$grp->commit();
			jsln('refresh();');
		}
		
		function saveDomain($xa){
			$dom = Domain($xa->id);
			if(isset($xa->own)) $dom->own = smdb($xa->own);
			if(isset($xa->grp)) $dom->grp = smdb($xa->grp);
			if(isset($xa->ini)) if(is_string($e = $dom->set_config($xa->ini))) httpE(418, "Config error: $e");
			if(!$e) httpE(418, "Commital failed");
			jsln('goTo("");');
		}
		
		function testDatabase($xa){
			$ini = parse_ini_string($xa->get('ini'), 1);
			if(!$ini){
				echo 'The ini is malformed: it cannot be parsed';
				return;
			}
			if(!isset($ini['name'])){
				echo 'No database name was given. Reference the real database name.';
				return;
			}
			if(!isset($ini['user'])){
				echo 'No database user is given.';
				return;
			}
			if(!isset($ini['pass'])){
				echo 'No password is given. Reference the database user\'s password as "pass".';
				return;
			}
			$dbn = $ini['name'];
			$ini = new ini(false, array_merge(array('type'=>'mysql', 'host'=>'localhost'), $ini));
			$al = sn()->call_abstractor($ini->type, $ini->user, $ini->pass, $ini->name, $ini->host);
			putenv('SMUOI_SUPPRESS_MYSQL_FATALITIES=1');
			$er = error_reporting(0);
			$suc = $al->open();
			error_reporting($er);
			if(!$suc){
				echo '<div style="padding:3px; border:1px dashed #900; color:#900; text-align:left">'.$al->last_error.'</div>';
				return;
			}
			echo "Succesfully connected to $dbn<br /><br />";
			$keys = array();
			$names = array();
			$packages = array();
			foreach($ini as $k=>$v){
				if(!is_array($v) || empty($v)) continue;
				$packages[] = $k;
				if(!$key = @$v['key']){
					echo "<strong style='color:red'>Failed</strong>: $k has no key defined";
					return;
				}
				if(isset($keys[$key])){
					echo "<strong style='color:red'>Failed</strong>: key '$key' is used by both ".$keys[$key]." and $k";
					return;
				}
				$keys[$key] = $k;
				if(!$name = @$v['name']){
					echo "<strong style='color:red'>Failed</strong>: $k has no table name defined";
					return;
				}
				if(isset($names[$name])){
					echo "<strong style='color:red'>Failed</strong>: table '$name' is used by both ".$names[$name]." and $k";
					return;
				}
				$names[$name] = $name;
				$path = substr($k, 0, strrpos($k, '/'));
				if(!is_file(PKG_DIR."/$path/Resources/package.sql")){
					echo "<strong style='color:red'>Failed</strong>: there doesn't seem to be any package at $path.";
					return;
				}
			}
			if(empty($packages)){
				echo "<strong style='color:red'>Failed</strong>: no packages found.";
				return;
			}
			if(isset($ini->keylen)){
				if(!is_integer($ini->keylen+0) || $ini->keylen < 1){
					echo "<strong style='color:red'>Failed</strong>: keylen must be positive integer";
					return;
				}
				if($ini->keylen > 2){
					$k = $ini->keylen;
					$pow = pow(37, $k);
					$p2 = pow(37, 2);
					echo "keylen is $k!  This gives you 37<sup>$k</sup> or $pow possible tables. A keylen of 2 gives you $p2 - isn't that enough?"
					. "<br /><br />Be aware columns may not be able to hold ids beyond a certain length, and it is highly unlikely a given package was tested with an id prefix greater than 2.";
					return;
				}
			}
			echo "Package configuration appears to be OK.<br /><br />Note that package paths and dependencies are not tested.";
			$nn = $xa->get('name');
			if($nn !== $xa->get('dbid')){
				if(!$nn = alphanum($nn)) echo "<br /><br /><strong style='color:red'>Failed</strong>: Name is blank or contains bad characters."; 
				elseif(is_file(ETC_DIR."/db/$nn")) echo "<br /><br /><strong style='color:red'>Failed</strong>: Another db with the name $nn already exists.";
				else echo "<br /><br />Rename database to $nn: ok";
			}
			if($xa->dbid == DOM_ID){
				 echo "<br /><br /><strong style='color:red'>You can't alter the running database.  Sign into another project's desktop to alter the database ".DOM_ID."</strong>";	
			}
			return $ini;
		}
		
		
		function saveDatabase($xa){
			if(!$ini = $this->testDatabase($xa)) return;
			ob_clean();
			ob_start();
			$dbn = $xa->dbid;
			$nn = $xa->name;
			if($dbn == DOM_ID){
				echo "<br /><br /><strong style='color:red'>You can't alter the running database.  Sign into another project's desktop to alter the database ".DOM_ID."</strong>";	
				return;
			}
			if($nn !== $dbn){
				if(!$nn = alphanum($nn)){
					echo "<strong style='color:red'>Failed</strong>: Name is blank or contains bad characters."; 
					return;
				}elseif(!rename(ETC_DIR."/db/$dbn", ETC_DIR."/db/$nn")){
					echo "<strong style='color:red'>Failed</strong>: Could not rename database to $nn";
					return;
				}
				$dbn = $nn;
			}
			$file = ETC_DIR."/db/$dbn";
			$new = new ini;
			$new->set_file_path($file);
			$new->set_content($ini);
			if(!$new->write()) echo $new->error();
			else echo "Written to $file OK";
			jsln('unflagChange();');
			if($xa->dbid !== $xa->name){
				echo "<br /><br />Opening database as '$nn'...";
				jsln("setTimeout(function(){ window.location.href = '$nn' }, 2000);");
			}
		}
	}
?>